iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0
生成式 AI

LLM 學習筆記 - 從 LLM 輸入問題,按下 Enter 後會發生什麼事?系列 第 19

Day 19. Transformer: 從做 LLM 中完成第一版 GPT

  • 分享至 

  • xImage
  •  

組裝 Transformer

隨著這幾天的逐步逐步的實做,目前一個 Transformer 模組中要有的元素都已經有了,下一步是要將許多 Transformer 組裝起來變成一個 Transformer Block:

class TransformerBlock(nn.Module):
    def __init__(self, cfg):
        super().__init__()
        self.att = MultiHeadAttention(
            d_in=cfg["emb_dim"],
            d_out=cfg["emb_dim"],
            context_length=cfg["context_length"],
            num_heads=cfg["n_heads"], 
            dropout=cfg["drop_rate"],
            qkv_bias=cfg["qkv_bias"])
        self.ff = FeedForward(cfg)
        self.norm1 = LayerNorm(cfg["emb_dim"])
        self.norm2 = LayerNorm(cfg["emb_dim"])
        self.drop_shortcut = nn.Dropout(cfg["drop_rate"])

    def forward(self, x):
        shortcut = x
        x = self.norm1(x)
        x = self.att(x)  
        x = self.drop_shortcut(x)
        x = x + shortcut 

        shortcut = x
        x = self.norm2(x)
        x = self.ff(x)
        x = self.drop_shortcut(x)
        x = x + shortcut 

        return x

完整的順序如下,input 是 tokenize 並經過 Embedding 的矩陣,接著先經過一次 normalization layer,接著透過 multi head attention module 並且 dropout 出結果,同時在 normalization 前拉出一個 shortcut connection 連結。

這一段的結果會再經過一次 normalization 送進 feed forward 中,feed forward 又包括了 linear layer 與 GELU activation 後,再送出 dropout 第一次,同樣的 input & output 會透過 shortcut connection 連結。

這一整塊便是 Transformer 模組,綜觀來看,從最一開始經過 attention 讓我們可以掌握文字之間關連,到後續 feed forward 單純去預測什麼是最佳文字結果。

而過程中即便維度會轉置、重新編碼計算,但始終保持最終輸出結果不變也是其中一個輸出重點。

組裝 GPT

最終經過 transformer 後,會再做一次最後最後一次的 normalization 最後透過 linear layer 輸出完整結果。

class GPTModel(nn.Module):
    def __init__(self, cfg):
        super().__init__()
        self.tok_emb = nn.Embedding(cfg["vocab_size"], cfg["emb_dim"])
        self.pos_emb = nn.Embedding(cfg["context_length"], cfg["emb_dim"])
        self.drop_emb = nn.Dropout(cfg["drop_rate"])
        
        self.trf_blocks = nn.Sequential(
            *[TransformerBlock(cfg) for _ in range(cfg["n_layers"])])
        
        self.final_norm = LayerNorm(cfg["emb_dim"])
        self.out_head = nn.Linear(
            cfg["emb_dim"], cfg["vocab_size"], bias=False
        )

    def forward(self, in_idx):
        batch_size, seq_len = in_idx.shape
        tok_embeds = self.tok_emb(in_idx)
        pos_embeds = self.pos_emb(torch.arange(seq_len, device=in_idx.device))
        x = tok_embeds + pos_embeds  # Shape [batch_size, num_tokens, emb_size]
        x = self.drop_emb(x)
        x = self.trf_blocks(x)
        x = self.final_norm(x)
        logits = self.out_head(x)
        return logits

於是我們再將 Transformer Block 加入進完整的 GPTModel Class 之中。接著再加入生成文字的 function:

def generate_text_simple(model, idx, max_new_tokens, context_size):
    for _ in range(max_new_tokens):
        idx_cond = idx[:, -context_size:]
        
        with torch.no_grad():
            logits = model(idx_cond)
        
        logits = logits[:, -1, :]  
        probas = torch.softmax(logits, dim=-1)  # (batch, vocab_size)
        idx_next = torch.argmax(probas, dim=-1, keepdim=True)  # (batch, 1)
        idx = torch.cat((idx, idx_next), dim=1)  # (batch, n_tokens+1)

    return idx

這個 function 會負責讀取一段文字,生成下一個文字後加入在文字之後,接著繼續生成下一個。而也因為我們還沒訓練模型,所以先關閉 dropout 等等的模組。

最終就可以做到一個胡言亂語生成文字的 GPT 模組了。


上一篇
Day 18. Shorted Connection: 從做 LLM 避免梯度消失
下一篇
Day 20. Cross-Entropy: 從做 LLM 中來看怎麼 Pre Train
系列文
LLM 學習筆記 - 從 LLM 輸入問題,按下 Enter 後會發生什麼事?24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言